#pragma once

#include <queue>
#include <mutex>
#include <pthread.h>
#include <vector>

#include "task.hpp"
#include "log_pro.hpp"

#define THREADNUM 5//线程池线程数

class ThreadPool
{
private:
    std::queue<Task> _task_queue;
    int _num;   // 线程数量
    bool _stop; // 线程池是否暂停
    pthread_mutex_t _mtx;
    pthread_cond_t _cond;

    static ThreadPool *threadPool_ptr;

public:
    static ThreadPool *getThreadPool()
    {
        if (threadPool_ptr == nullptr)
        {
            static pthread_mutex_t _threadPoolMutex = PTHREAD_MUTEX_INITIALIZER;
            pthread_mutex_lock(&_threadPoolMutex);
            if (threadPool_ptr == nullptr)
            {
                threadPool_ptr = new ThreadPool;
                threadPool_ptr->init();
            }
            pthread_mutex_unlock(&_threadPoolMutex);
        }
        return threadPool_ptr;
    }

    void init()
    {
        pthread_mutex_init(&_mtx, nullptr);
        pthread_cond_init(&_cond,nullptr);

        pthread_t pid; // 我们不需要记录我们的线程pid，因为线程会自动routine函数去运行拿任务
        for (int i = 0; i < _num; i++)
        {
            int ret = pthread_create(&pid, nullptr, routine, this);
            if (ret != 0)
            {
                lg(FATAL, "thread crate fail!");
                exit(-1);
            }
        }
        lg(NOTICE, "create %d threadPool success!",_num);
    }

    static void *routine(void *argv) // 线程池中线程运行的函数
    {
        ThreadPool *ptr = (ThreadPool *)argv;
        Task t;

        while (true)
        {
            ptr->lock();
            while (ptr->taskQueueIsEmpty())
            {
                ptr->waitThread(); // 等待被唤醒
            }
            ptr->popTask(t);
            ptr->unlock();
            t.disponse(); // 调用任务类的处理函数来处理任务
        }
    }

    ~ThreadPool()
    {
    }
    bool taskQueueIsEmpty()
    {
        return _task_queue.size() == 0;
    }

    void pushTask(const Task &task)
    {
        lock();
        _task_queue.push(task);
        unlock();
        wakeupThread();
    }
    void popTask(Task &task)
    {
        task = _task_queue.front();
        _task_queue.pop();
    }

private:
    ThreadPool(int num=THREADNUM):_num(num)
    {
    }
    void lock()
    {
        pthread_mutex_lock(&_mtx);
    }
    void unlock()
    {
        pthread_mutex_unlock(&_mtx);
    }
    void waitThread()
    {
        pthread_cond_wait(&_cond, &_mtx);
    }
    void wakeupThread()
    {
        pthread_cond_signal(&_cond);
    }
};

ThreadPool *ThreadPool::threadPool_ptr = nullptr;